<template>
  <div class="comp-scroll-container" :style="{ height: height }">
    <scroll-view
      class="scroll-view"
      :scroll-y="true"
      :refresher-enabled="refresherEnabled"
      :refresher-triggered="isRefreshing"
      :refresher-threshold="refresherThreshold"
      @refresherrefresh="onRefresh"
      @scrolltolower="onLoadMore"
      @scroll="onScroll"
    >
      <!-- 自定义下拉刷新样式 -->
      <div v-if="customRefresher" class="custom-refresher">
        <slot name="refresher">
          <div class="default-refresher">
            <span v-if="isRefreshing">刷新中...</span>
            <span v-else>下拉刷新</span>
          </div>
        </slot>
      </div>

      <!-- 内容区域 -->
      <slot></slot>

      <!-- 底部加载状态 -->
      <div class="loading-more" v-if="showLoadingMore">
        <slot name="loading-more">
          <div class="default-loading-more">
            <span v-if="isLoadingMore">加载中...</span>
            <span v-else-if="loadAll">已加载全部</span>
            <span v-else>上拉加载更多</span>
          </div>
        </slot>
      </div>

      <!-- 空状态 -->
      <div class="empty-state" v-if="isEmpty">
        <slot name="empty">
          <div class="default-empty">
            <span>暂无数据</span>
          </div>
        </slot>
      </div>
    </scroll-view>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'

// 定义组件属性
interface Props {
  /** 容器高度 */
  height?: string
  /** 是否启用下拉刷新 */
  refresherEnabled?: boolean
  /** 自定义下拉刷新样式 */
  customRefresher?: boolean
  /** 下拉刷新阈值 */
  refresherThreshold?: number
  /** 是否显示底部加载更多 */
  showLoadingMore?: boolean
  /** 是否已加载全部数据 */
  loadAll?: boolean
  /** 是否为空状态 */
  isEmpty?: boolean
  /** 节流时间间隔(ms) */
  throttleTime?: number
}

const props = withDefaults(defineProps<Props>(), {
  height: '100vh',
  refresherEnabled: true,
  customRefresher: false,
  refresherThreshold: 45,
  showLoadingMore: true,
  loadAll: false,
  isEmpty: false,
  throttleTime: 500
})

// 定义事件
const emit = defineEmits<{
  /** 刷新事件 */
  (e: 'refresh'): void
  /** 加载更多事件 */
  (e: 'loadMore'): void
  /** 滚动事件 */
  (e: 'scroll', detail: { scrollTop: number; direction: 'up' | 'down' }): void
}>()

// 组件状态
const isRefreshing = ref(false)
const isLoadingMore = ref(false)
const lastScrollTop = ref(0)
const lastRefreshTime = ref(0)
const lastLoadMoreTime = ref(0)

// 节流函数
const throttle = <T extends (...args: any[]) => any>(fn: T, delay: number) => {
  let lastTime = 0
  return (...args: Parameters<T>): ReturnType<T> | undefined => {
    const now = Date.now()
    if (now - lastTime >= delay) {
      lastTime = now
      return fn(...args)
    }
    return undefined
  }
}

// 处理下拉刷新
const onRefresh = () => {
  const now = Date.now()
  if (now - lastRefreshTime.value < props.throttleTime) return
  
  lastRefreshTime.value = now
  isRefreshing.value = true
  emit('refresh')
}

// 处理上拉加载更多
const onLoadMore = throttle(() => {
  if (isLoadingMore.value || props.loadAll) return
  
  const now = Date.now()
  if (now - lastLoadMoreTime.value < props.throttleTime) return
  
  lastLoadMoreTime.value = now
  isLoadingMore.value = true
  emit('loadMore')
}, props.throttleTime)

// 处理滚动事件
const onScroll = throttle((e: any) => {
  const scrollTop = e.detail.scrollTop
  const direction = scrollTop > lastScrollTop.value ? 'down' : 'up'
  lastScrollTop.value = scrollTop
  
  emit('scroll', { scrollTop, direction })
}, 100)

// 暴露给父组件的方法
const finishRefresh = () => {
  isRefreshing.value = false
}

const finishLoadMore = (loadAll = false) => {
  isLoadingMore.value = false
  if (loadAll) {
    props.loadAll = loadAll
  }
}

const scrollTo = (position: number, duration = 300) => {
  // 在小程序中实现滚动到指定位置
  uni.createSelectorQuery()
    .select('.scroll-view')
    .node()
    .exec((res) => {
      if (res[0]?.node) {
        res[0].node.scrollTo({ top: position, duration })
      }
    })
}

const scrollToTop = (duration = 300) => {
  scrollTo(0, duration)
}

const reset = () => {
  isRefreshing.value = false
  isLoadingMore.value = false
  scrollToTop(0)
}

// 监听loadAll变化
watch(
  () => props.loadAll,
  (newVal) => {
    if (newVal) {
      isLoadingMore.value = false
    }
  }
)

// 暴露组件方法
defineExpose({
  finishRefresh,
  finishLoadMore,
  scrollTo,
  scrollToTop,
  reset
})
</script>

<style scoped>
.comp-scroll-container {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.scroll-view {
  height: 100%;
  width: 100%;
}

.custom-refresher {
  width: 100%;
}

.default-refresher,
.default-loading-more,
.default-empty {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20rpx 0;
  color: #999;
  font-size: 24rpx;
}

.loading-more {
  width: 100%;
  text-align: center;
}

.empty-state {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200rpx;
  width: 100%;
}
</style>